如果覺得文章對你有所啟發,可以考慮用 🌟 支持 Gthulhu 專案,短期目標是集齊 300 個 🌟 藉此被 CNCF Landscape 採納 [ref]。
來源:https://github.com/Gthulhu/qumun/
昨天的文章中我們快速的導覽了 scx_rustland 的設計精神,起初,我決定用 golang 打造 Linux Scheduler 的原因也很單純,就是覺得如果能弄出來會很酷。
然而,即使 Golang 有 aqua security 包好的 libbpfgo,要移植 rustland 的成果仍會遇到非預期的問題。
這邊先撇開 libbpfgo 缺失的 API 實作,就談談我在移植的過程中忽略的第一件事。當我將缺失的 API 補足後,scx_rustland 的 eBPF program 確實能夠被我所實作的 user space app 載入至 kernel,但是只要程式一被載入後,系統就會停擺約 5 秒鐘,直到 scx_rustland 被 watch dog 剔除。
起初,我花費大量的心思在 user ring buffer 以及 ring buffer 的除錯,但後續使用了 syscall type 的 eBPF program 驗證兩者的功能性後才排除了這個問題。後來實在對這件事沒有頭緒,我才向 Andrea Righi 求助。
顯然,大神也被這個問題困擾過,因為他馬上給予我肯定的回答,且明確的指出是 page fault 造成的 deadlock。Andrea Righi 甚至為了解決 page fault 造成的“效能問題”實作了一個 buddy allocator。
值得一提的是,Page Fault 對 scx_rustland 的影響僅僅是「開銷變大」,但對於 scx_goland 是直接造成死機(deadlock)。兩者都使用同樣的 eBPF program 卻有截然不同的結果,經過一番研究後發現是 cgo 間接造成的問題:
而 scx_rustland 需要知道 user space scheduler 的 PID,讓 user space scheduler 能直接被 eBPF program 排程,不靠 user space scheduler 自己介入。這會導致 golang 產生的 thread 無法被 eBPF program 識別,因為 golang rutime 衍伸的 thread 的 PID 與 user space scheduler 的 PID 並不同。
來源:https://www.cnblogs.com/LoyenWang/p/12116570.html
當 page fault 發生時,出問題的 process 會進入 kernel mode 來解決這個問題,這會讓 user space scheduler 對應的多個 thread entity 在發生 page fault 時無法排程自己生成的 goroutine,最後造成 deadlock。
這個問題的解法是改成識別 TGID,如果 process 的 TGID 等於 user space scheduler 的 PID,一律由 eBPF program 排程。
效能改善的部分則是盡可能使用 pre-allocated memory,且配合 Mlockall
減少 page fault 發生的頻率。
補充:
起初,scx_rustland 也會對處於 page fault 的 process 進行特殊處理,詳見:
- https://github.com/Gthulhu/qumun/blob/96cebdd3348b46ae96044d0269cd824213e56772/main.bpf.c#L854
- https://github.com/Gthulhu/qumun/blob/96cebdd3348b46ae96044d0269cd824213e56772/main.bpf.c#L277
後續又因為這個機制會讓沒有處於 page fault 的任務發生 starvation 而在該 commit 中移除。